﻿using System;
using System.Collections.Generic;
using System.Linq;
using Sustainalytics.ClientDW.Entities;
using Sustainalytics.ESGRatings.BusinessLogic.Computing;
using Sustainalytics.ESGRatings.DataContract.ESG;
using Sustainalytics.ReportGenerator.BL;

namespace Sustainalytics.HistoricalData.ComputationTool
{
    public class ESGToHistoricalData
    {
        private readonly ESGRatingsOptionsDto _options;
        //private readonly ESGComputeResult _result;

        //public ESGToHistoricalData(ESGComputeResult result)
        //{
        //    _result = result;
        //}

        //public void GetRatings(DateTime date, Dictionary<Guid, CompanyHistoricalPerformance> data)
        //{
        //    if (_result.Ratings == null)
        //        return;

        //    if (((_result.ComputeOptions & ESGRatingsOptions.IncludeFlags.IncludeRatings) == 0))
        //        return;

        //    int companiesCount = _result.Ratings.CompaniesCount;

        //    var ratings = _result.Ratings;

        //    var ax = (from ci in Enumerable.Range(0, companiesCount)
        //              let companyId = ratings.CompanyIndices[ci]
        //              select new KeyValuePair<int, CompanyHistoryData>(companyId, new CompanyHistoryData { Date = date, CompanyId = GetCompanyId(companyId) })
        //             ).ToDictionary(c => c.Key, c => c.Value);

        //    GetRating(companiesCount, ratings, ax);

        //    foreach (var companyHistoryData in ax)
        //    {
        //        CompanyHistoricalPerformance content;
        //        Guid companyId = GetCompanyId(companyHistoryData.Key);
        //        if (!data.TryGetValue(companyId, out content))
        //        {
        //            content = new CompanyHistoricalPerformance
        //            {
        //                Id = companyId,
        //                Last36Months = new List<CompanyHistoryData>()
        //            };
        //            data.Add(companyId, content);
        //        }
        //        content.Last36Months.Add(companyHistoryData.Value);
        //    }
        //}

        //private Guid GetCompanyId(int index)
        //{
        //    return _result.CompaniesMap[index];
        //}

        //private int GetGroupId(int companyIndex)
        //{
        //    int[] heads = _result.CompaniesHeadsGroups;
        //    int headsCount = heads.Length;
        //    for (int i = 0; i < headsCount; i++)
        //    {
        //        if (heads[i] > companyIndex)
        //            return i;
        //    }
        //    return headsCount;
        //}

        //private void GetRating(int companiesCount, RatingsResult ratings, Dictionary<int, CompanyHistoryData> ax)
        //{
        //    for (int i = 0; i < companiesCount; i++)
        //    {
        //        var clusterIndex = _result.Configuration.GetAllClusterIndex();
        //        var ratingIndex = clusterIndex * companiesCount + i;
        //        var companyId = ratings.CompanyIndices[ratingIndex];
        //        var groupIndex = GetGroupId(companyId);

        //        var companyHistoricalPerformance = ax[companyId];

        //        companyHistoricalPerformance.OverallScore = ratings.Ratings[ratingIndex];
        //        companyHistoricalPerformance.OverallAverage = ratings.Group_Avgs[groupIndex];
        //        companyHistoricalPerformance.OverallBestInClass = ratings.Group_Maxs[groupIndex];

        //        clusterIndex = _result.Configuration.EIndex + 1;
        //        ratingIndex = clusterIndex * companiesCount + i;

        //        companyId = ratings.CompanyIndices[ratingIndex];
        //        groupIndex = GetGroupId(companyId) + clusterIndex * ratings.ClusterGroupsCount;

        //        companyHistoricalPerformance.EnvironmentScore = ratings.Ratings[ratingIndex];
        //        companyHistoricalPerformance.EnvironmentAverage = ratings.Group_Avgs[groupIndex];
        //        companyHistoricalPerformance.EnvironmentBestInClass = ratings.Group_Maxs[groupIndex];

        //        clusterIndex = _result.Configuration.GIndex + 1;
        //        ratingIndex = clusterIndex * companiesCount + i;
        //        companyId = ratings.CompanyIndices[ratingIndex];
        //        groupIndex = GetGroupId(companyId) + clusterIndex * ratings.ClusterGroupsCount;

        //        companyHistoricalPerformance.GovernanceScore = ratings.Ratings[ratingIndex];
        //        companyHistoricalPerformance.GovernanceAverage = ratings.Group_Avgs[groupIndex];
        //        companyHistoricalPerformance.GovernanceBestInClass = ratings.Group_Maxs[groupIndex];

        //        clusterIndex = _result.Configuration.SIndex + 1;
        //        ratingIndex = clusterIndex * companiesCount + i;
        //        companyId = ratings.CompanyIndices[ratingIndex];
        //        groupIndex = GetGroupId(companyId) + clusterIndex * ratings.ClusterGroupsCount;

        //        companyHistoricalPerformance.SocialScore = ratings.Ratings[ratingIndex];
        //        companyHistoricalPerformance.SocialAverage = ratings.Group_Avgs[groupIndex];
        //        companyHistoricalPerformance.SocialBestInClass = ratings.Group_Maxs[groupIndex];
        //    }
        //}

        private readonly ICompanyFilter _filter;

        public ESGToHistoricalData(ESGRatingsOptionsDto options, ComputationEngine engine)
        {
            this._options = options;
            _filter = GetFilter(options, engine);
        }

        private static ICompanyFilter GetFilter(ESGRatingsOptionsDto options, ComputationEngine engine)
        {
            if (options.CompaniesIds != null && options.CompaniesIds.Count > 0)
            {
                var additionalCompaniesIds = new List<Guid>();
                if (options.IncludeCompaniesInGroup)

                    foreach (var companyId in options.CompaniesIds)
                    {
                        var companiesToAdd = engine.GetCompaniesInComparativeGroup(companyId, options.MatrixId, options.RefUnivId, options.GroupBy);
                        if (companiesToAdd != null)
                            additionalCompaniesIds.AddRange(companiesToAdd);
                    }


                additionalCompaniesIds.AddRange(engine.GetMatchingCompanies(options.MatrixId, options.RefUnivId,
                         options.PeerGroups, options.IndustryGroups));
                return new CompanyFilter(options.CompaniesIds.Union(additionalCompaniesIds));
            }

            if (options.IndustryGroups == null || options.IndustryGroups.Count == 0)
                if ((options.PeerGroups == null) || options.PeerGroups.Count == 0)
                    return null;

            return new CompanyFilter(engine.GetMatchingCompanies(options.MatrixId, options.RefUnivId, options.PeerGroups, options.IndustryGroups));
        }

        public void GetRatings(DateTime date, ESGComputeResult result, ICollection<Guid> companyIds, Dictionary<Guid, CompanyHistoricalPerformance> data)
        {


            var dto = new ESGRatingsDto
            {
                IndicatorsGroups = ToIndicatorsGroupsDto(result.Configuration),
                SetId = result.SetId,
            };

            var utils = new ESGComputeMap(result, _filter);


            if (_options.IncludeIndWeightedScores)
            {
                dto.IndicatorsCodes = result.Configuration.Codes.ToArray();
                dto.Indicators = utils.GetIndicators().ToList();
            }

            if (_options.IncludeRatings)
            {
                dto.Ratings = utils.GetRatings().ToList();
            }


            if (_options.IncludeAggregatedScores && !_options.IncludeTopPerformersInfo)
            {
                dto.Groups = utils.GetGroups().ToArray();
            }


            if (_options.IncludeAggregatedScores && _options.IncludeTopPerformersInfo)
            {
                dto.Groups = utils.GetGroupsWithTopCompanies().ToArray();
            }

            var adapter = new ESGRatingsAdapter(dto);

            CompanyHistoricalPerformance content;
            foreach (var companyId in companyIds)
            {
                if (!data.TryGetValue(companyId, out content))
                {
                    content = new CompanyHistoricalPerformance
                    {
                        Id = companyId,
                        Last36Months = new List<CompanyHistoryData>()
                    };
                    data.Add(companyId, content);
                }

                var esgData = adapter.GetEsgData(companyId);
                var esgAvg = adapter.GetESGAvg(companyId);
                var esgBest = adapter.GetBestInClass(companyId);
                var companyHistoryData = new CompanyHistoryData()
                {
                    CompanyId = companyId,
                    Date = date,
                    EnvironmentAverage = esgAvg.EAvg,
                    EnvironmentBestInClass = esgBest.EBestInClass,
                    EnvironmentScore = esgData.EnvironmentScore,

                    GovernanceScore = esgData.GovernanceScore,
                    GovernanceAverage = esgAvg.GAvg,
                    GovernanceBestInClass = esgBest.GBestInClass,

                    SocialScore = esgData.SocialScore,
                    SocialAverage = esgAvg.SAvg,
                    SocialBestInClass = esgBest.SBestInClass,

                    OverallBestInClass = esgBest.OverallBestInClass,
                    OverallScore = esgData.Score,
                    OverallAverage = esgAvg.OverallAvg,

                };
                content.Last36Months.Add(companyHistoryData);
            }

        }

        private static IndicatorsGroupsDto ToIndicatorsGroupsDto(IndicatorsConfiguration configuration)
        {
            var indicatorsGroups = new IndicatorsGroupsDto();

            indicatorsGroups.All = new ClusterDto { Id = 0, Name = "All" };
            indicatorsGroups.Themes = new List<ClusterDto>();
            indicatorsGroups.Clusters = new List<ClusterDto>();
            int index = 1;
            foreach (var themeMap in configuration.EsgMap)
            {
                indicatorsGroups.Themes.Add(new ClusterDto { Id = index, Name = themeMap });
                index++;
            }
            foreach (var themeMap in configuration.ClustersMap)
            {
                indicatorsGroups.Clusters.Add(new ClusterDto { Id = index, Name = themeMap });
                index++;
            }
            return indicatorsGroups;
        }



    }
}